Skip to content

feat(impact): ship deterministic commandf impact - #27

Merged
TheHalfMoon merged 9 commits into
mainfrom
impl/cf12-impact-cli
Aug 26, 2026
Merged

feat(impact): ship deterministic commandf impact#27
TheHalfMoon merged 9 commits into
mainfrom
impl/cf12-impact-cli

Conversation

@TheHalfMoon

Copy link
Copy Markdown
Owner

Stack

CF-12 implementation Stack B for tasks T020-T025.

Base: canonical Stack A merge d46591f0f7224d49fda0d89a6a79cc418fba534e.

Summary

Ship the user-visible commandf impact CLI as a thin adapter over the canonical CF-12 library contract and add dedicated deterministic proof.

Changes

  • add commandf impact <package> with explicit before/after lock/cache inputs and JSON-only V1 output;
  • reuse existing structural diff, verified package-cache reads, CF-11G Context Graph construction, and build_impact_report;
  • keep impact evidence separate from BREAKING/RISKY/ADDITIVE compatibility authority;
  • fail closed on schema-v1 graph evidence, missing/corrupt cache archives, ambiguous selected package identity, and existing bounded artifact failures;
  • add CLI behavior coverage for help, byte determinism, authority separation, schema-v1 refusal, and corrupt cache refusal;
  • add cf12-impact-proof using the immutable Rust 1.97.1 container and pinned actions;
  • emit CF12_IMPACT_SHA256=<sha256> and retain the checksum as a short-lived workflow artifact;
  • assert the proof leaves the repository clean.

Explicit non-goals

  • no compatibility severity inference from impact reachability;
  • no CF-06 / HL7 production-pin change;
  • no frozen CF-10 corpus change;
  • no lock schema change;
  • no network canonical completion;
  • no graph database, vector, model, or agent authority;
  • no new Rust dependency.

Keep Draft until all applicable exact-head workflows, the dedicated CF-12 proof, and independent review are terminal and clean. Final task/convergence evidence will be recorded only after immutable run/artifact identities exist.

@coderabbitai

coderabbitai Bot commented Aug 26, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

Next included review available in 38 seconds.

View limit details

Limit details: You’ve used all 10 included reviews currently available.

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: fd7c57e3-8575-49cb-85d8-a3e0cec275a6

📥 Commits

Reviewing files that changed from the base of the PR and between d46591f and 6d8e22b.

📒 Files selected for processing (5)
  • .github/workflows/cf12-impact-proof.yml
  • crates/commandf-cli/src/impact.rs
  • crates/commandf-cli/src/main.rs
  • crates/commandf-cli/tests/impact_behavior.rs
  • crates/commandf-cli/tests/impact_determinism_proof.rs
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch impl/cf12-impact-cli

Comment @coderabbitai help to get the list of available commands.

@qodo-code-review

Copy link
Copy Markdown

ⓘ Your Qodo trial ends soon. Ask your workspace admin to set up billing to keep reviews running after the trial. Manage billing

Copy link
Copy Markdown
Owner Author

@coderabbitai review

Copy link
Copy Markdown
Owner Author

/review

@coderabbitai

coderabbitai Bot commented Aug 26, 2026

Copy link
Copy Markdown
⚠️ Action not completed

Head commit changed.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 26, 2026

Copy link
Copy Markdown
⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@TheHalfMoon
TheHalfMoon marked this pull request as ready for review August 26, 2026 07:14

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@TheHalfMoon
TheHalfMoon merged commit 9e462cb into main Aug 26, 2026
8 of 9 checks passed
@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Add deterministic commandf impact CLI and proof

✨ Enhancement 🧪 Tests ⚙️ Configuration changes 🕐 20-40 Minutes

Grey Divider

AI Description

• Adds deterministic commandf impact JSON from explicit before/after lock and cache states.
• Rejects unsupported schemas, ambiguous packages, and missing or corrupt cached archives.
• Proves byte-identical output and authority separation through CLI tests and pinned CI.
Diagram

graph TD
  Inputs["Lock/cache states"] --> Validate["Validate inputs"] --> Diff["Structural diff"] --> Graphs["Context graphs"] --> Report["Impact report"] --> JSON["JSON output"]
  CLI["Impact CLI"] --> Validate
  Inputs --> Graphs
Loading
High-Level Assessment

The thin-adapter approach is optimal: it composes the existing structural diff, verified cache, context graph, and impact-report contracts rather than creating competing CLI-specific authority. Duplicating those algorithms or inferring compatibility severity from reachability would increase drift and violate the intended authority boundary.

Files changed (5) +581 / -0

Enhancement (2) +117 / -0
impact.rsImplement the impact CLI adapter +90/-0

Implement the impact CLI adapter

• Loads and validates schema-v2 before/after lockfiles, uniquely selects the requested package, and verifies both cache archives. It composes structural diffing, context graph construction, and impact reporting into deterministic JSON bytes while failing closed on invalid evidence.

crates/commandf-cli/src/impact.rs

main.rsExpose and dispatch the impact subcommand +27/-0

Expose and dispatch the impact subcommand

• Adds 'commandf impact' arguments for explicit before/after lockfiles and caches with JSON output. Dispatches the parsed inputs to the dedicated impact adapter and writes its serialized report to stdout.

crates/commandf-cli/src/main.rs

Tests (2) +394 / -0
impact_behavior.rsCover impact CLI behavior and refusal paths +238/-0

Cover impact CLI behavior and refusal paths

• Verifies help text, byte-identical JSON, expected impact evidence, and separation from compatibility severity. It also confirms schema-v1 locks and corrupt cache archives fail without producing stdout.

crates/commandf-cli/tests/impact_behavior.rs

impact_determinism_proof.rsProve byte-identical impact output +156/-0

Prove byte-identical impact output

• Builds synthetic before/after package states, executes the impact command twice offline, and asserts identical output. The proof emits a SHA-256 marker consumed by the dedicated CI workflow.

crates/commandf-cli/tests/impact_determinism_proof.rs

Other (1) +70 / -0
cf12-impact-proof.ymlAdd pinned deterministic impact proof workflow +70/-0

Add pinned deterministic impact proof workflow

• Runs the impact determinism proof in an immutable Rust 1.97.1 container with pinned actions. It captures the reported SHA-256 checksum, verifies the repository remains clean, and retains the evidence artifact for three days.

.github/workflows/cf12-impact-proof.yml

@qodo-code-review

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (1) 📜 Skill insights (0)

Grey Divider


Remediation recommended

1. Ambiguous package error untested 📘 Rule violation ▣ Testability
Description
The new duplicate-package rejection in select_locked_package has no automated test that constructs
an ambiguous lockfile and asserts the CLI error behavior. This leaves a distinct business-logic
conflict branch unverified.
Code

crates/commandf-cli/src/impact.rs[R83-86]

+    if matches.next().is_some() {
+        return Err(io::Error::new(
+            io::ErrorKind::InvalidData,
+            format!("package {package_name} appears more than once in the lockfile"),
Relevance

●●● Strong

The repository accepts explicit tests for boundary and failure behavior, and this distinct conflict
branch is straightforward to exercise.

PR-#10
PR-#12

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Compliance rule 2717396 requires a test for every distinct failure or conflict branch. The added
code explicitly rejects a second matching package, while the PR's impact behavior tests cover
schema-v1 and corrupt-cache failures but never create duplicate selected-package entries.

Rule 2717396: Test error and conflict branches in business logic handlers
crates/commandf-cli/src/impact.rs[83-87]
crates/commandf-cli/tests/impact_behavior.rs[73-107]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Add deterministic automated coverage for the `commandf impact` branch that rejects duplicate entries for the selected package.

## Issue Context
Construct a schema-v2 lockfile containing the requested package more than once, invoke the shipped CLI, and assert the nonzero exit status, empty stdout, and exact duplicate-package diagnostic.

## Fix Focus Areas
- crates/commandf-cli/src/impact.rs[83-87]
- crates/commandf-cli/tests/impact_behavior.rs[73-107]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Cache verification race 🐞 Bug ☼ Reliability
Description
The selected archive is verified, discarded, and then reopened with plain fs::read, so a cache
object changed between those operations can supply bytes that do not match the lock digest while the
diff still labels them with that digest. This breaks the verified-cache trust boundary and can
produce an internally inconsistent impact report.
Code

crates/commandf-cli/src/impact.rs[R27-30]

+    before_cache.verify(&before_locked.sha256)?;
+    after_cache.verify(&after_locked.sha256)?;
+
+    let before_bytes = read_locked_archive(&before_cache, before_locked)?;
Relevance

●●● Strong

Recent cache precedent accepts strengthening cache integrity and atomicity; reopening after
verification breaks the verified-cache boundary.

PR-#2

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
verify delegates to read_verified but throws away its returned bytes; read_verified performs
the digest check on the bytes it loaded. The CLI then opens the path again through
read_locked_archive, and those second bytes are passed to diff_package_archives under the
lockfile's digest, with no subsequent digest validation.

crates/commandf-cli/src/impact.rs[27-40]
crates/commandf-cli/src/impact.rs[60-67]
crates/commandf-pkg/src/cache.rs[63-85]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The impact CLI verifies a cache object and then rereads it outside `PackageCache`'s digest-checking boundary, allowing a check/use race and performing redundant I/O.

## Issue Context
`PackageCache::read_verified` returns the exact bytes whose digest it checked. Keep those bytes and pass them to the diff instead of calling `verify` followed by `fs::read`.

## Fix Focus Areas
- crates/commandf-cli/src/impact.rs[27-31]
- crates/commandf-cli/src/impact.rs[60-67]
- crates/commandf-pkg/src/cache.rs[63-85]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Inputs bypass size bounds 🐞 Bug ☼ Reliability
Description
impact::run uses unrestricted fs::read for user-supplied lockfiles and cache archives, allowing
oversized local inputs to allocate memory before parsing or bounded archive scanning can reject
them. The archive scanner's 512 MiB limit applies only to decompressed traversal after the complete
compressed archive is already resident in memory.
Code

crates/commandf-cli/src/impact.rs[R18-19]

+    let before_lockfile = Lockfile::from_slice(&fs::read(before_lock)?)?;
+    let after_lockfile = Lockfile::from_slice(&fs::read(after_lock)?)?;
Relevance

●●● Strong

Recent accepted precedents require compressed-input and decompression bounds for archive processing;
unrestricted reads violate that reliability pattern.

PR-#2
PR-#12

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Both lockfiles are fully read before Lockfile::from_slice, and PackageCache::read_verified/the
CLI's archive helper also use full-file fs::read. The only demonstrated archive bound is inside
scan_package_resources, where a GzDecoder traverses an already-present byte slice and limits
decompressed output, so it cannot cap the initial compressed-file allocation.

crates/commandf-cli/src/impact.rs[18-19]
crates/commandf-cli/src/impact.rs[27-31]
crates/commandf-cli/src/impact.rs[60-67]
crates/commandf-pkg/src/cache.rs[67-85]
crates/commandf-pkg/src/artifact_scan.rs[9-11]
crates/commandf-pkg/src/artifact_scan.rs[53-64]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new CLI reads arbitrary lock and cache files fully into memory before enforcing any input-size or decompression-work limits.

## Issue Context
Add explicit persisted-lock and compressed-archive byte limits at the read boundary, rejecting oversized files before allocation. Preserve the existing decompressed-byte, entry-count, and resource-size checks.

## Fix Focus Areas
- crates/commandf-cli/src/impact.rs[18-19]
- crates/commandf-cli/src/impact.rs[27-31]
- crates/commandf-pkg/src/cache.rs[67-85]
- crates/commandf-pkg/src/artifact_scan.rs[9-11]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context sources
✅ Compliance rules (platform): 13 rules
Review mode: ⚖️ Balanced: This adds a user-facing CLI path, workflow, cache and lockfile validation, graph/report integration, and substantial behavioral proof across multiple files; it carries real correctness and contract risk, but is not broad or defect-dense enough to warrant redundant extended review.

Grey Divider

Tip of the day
💡 Did you know, you can start a comment with 'qodo' or '@qodo' to chat about any finding

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment on lines +83 to +86
if matches.next().is_some() {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!("package {package_name} appears more than once in the lockfile"),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

1. Ambiguous package error untested 📘 Rule violation ▣ Testability

The new duplicate-package rejection in select_locked_package has no automated test that constructs
an ambiguous lockfile and asserts the CLI error behavior. This leaves a distinct business-logic
conflict branch unverified.
Agent Prompt
## Issue description
Add deterministic automated coverage for the `commandf impact` branch that rejects duplicate entries for the selected package.

## Issue Context
Construct a schema-v2 lockfile containing the requested package more than once, invoke the shipped CLI, and assert the nonzero exit status, empty stdout, and exact duplicate-package diagnostic.

## Fix Focus Areas
- crates/commandf-cli/src/impact.rs[83-87]
- crates/commandf-cli/tests/impact_behavior.rs[73-107]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +27 to +30
before_cache.verify(&before_locked.sha256)?;
after_cache.verify(&after_locked.sha256)?;

let before_bytes = read_locked_archive(&before_cache, before_locked)?;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

2. Cache verification race 🐞 Bug ☼ Reliability

The selected archive is verified, discarded, and then reopened with plain fs::read, so a cache
object changed between those operations can supply bytes that do not match the lock digest while the
diff still labels them with that digest. This breaks the verified-cache trust boundary and can
produce an internally inconsistent impact report.
Agent Prompt
## Issue description
The impact CLI verifies a cache object and then rereads it outside `PackageCache`'s digest-checking boundary, allowing a check/use race and performing redundant I/O.

## Issue Context
`PackageCache::read_verified` returns the exact bytes whose digest it checked. Keep those bytes and pass them to the diff instead of calling `verify` followed by `fs::read`.

## Fix Focus Areas
- crates/commandf-cli/src/impact.rs[27-31]
- crates/commandf-cli/src/impact.rs[60-67]
- crates/commandf-pkg/src/cache.rs[63-85]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +18 to +19
let before_lockfile = Lockfile::from_slice(&fs::read(before_lock)?)?;
let after_lockfile = Lockfile::from_slice(&fs::read(after_lock)?)?;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

3. Inputs bypass size bounds 🐞 Bug ☼ Reliability

impact::run uses unrestricted fs::read for user-supplied lockfiles and cache archives, allowing
oversized local inputs to allocate memory before parsing or bounded archive scanning can reject
them. The archive scanner's 512 MiB limit applies only to decompressed traversal after the complete
compressed archive is already resident in memory.
Agent Prompt
## Issue description
The new CLI reads arbitrary lock and cache files fully into memory before enforcing any input-size or decompression-work limits.

## Issue Context
Add explicit persisted-lock and compressed-archive byte limits at the read boundary, rejecting oversized files before allocation. Preserve the existing decompressed-byte, entry-count, and resource-size checks.

## Fix Focus Areas
- crates/commandf-cli/src/impact.rs[18-19]
- crates/commandf-cli/src/impact.rs[27-31]
- crates/commandf-pkg/src/cache.rs[67-85]
- crates/commandf-pkg/src/artifact_scan.rs[9-11]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant